package org.spiderflow.common.model;

import org.spiderflow.common.annotation.Comment;
import org.spiderflow.common.annotation.Return;
import org.spiderflow.common.annotation.Example;

import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * @author zsh
 */
public class Grammar {

    private String owner;

    private String method;

    private String comment;

    private String example;

    private String function;

    private List<String> returns;

    public String getOwner() {
        return owner;
    }

    public void setOwner(String owner) {
        this.owner = owner;
    }

    public String getMethod() {
        return method;
    }

    public void setMethod(String method) {
        this.method = method;
    }

    public String getFunction() {
        return function;
    }

    public void setFunction(String function) {
        this.function = function;
    }

    public String getComment() {
        return comment;
    }

    public void setComment(String comment) {
        this.comment = comment;
    }

    public String getExample() {
        return example;
    }

    public void setExample(String example) {
        this.example = example;
    }

    public List<String> getReturns() {
        return returns;
    }

    public void setReturns(List<String> returns) {
        this.returns = returns;
    }

    public static List<Grammar> findGrammars(Class<?> clazz, String function, String owner, boolean mustStatic) {
        return Arrays.stream(clazz.getDeclaredMethods())
                     .filter(m -> methodCheck(mustStatic, m))
                     .map(method -> createGrammar(function, owner, method))
                     .collect(Collectors.toList());
    }

    private static Grammar createGrammar(String function, String owner, Method method) {
        Grammar grammar = new Grammar();
        grammar.setMethod(method.getName());
        Optional.ofNullable(method.getAnnotation(Comment.class))
                .ifPresent(comment -> grammar.setComment(comment.value()));
        Optional.ofNullable(method.getAnnotation(Example.class))
                .ifPresent(example -> grammar.setExample(example.value()));
        List<String> returnTypes =
                Optional.ofNullable(method.getAnnotation(Return.class))
                        .map(returns -> Arrays.stream(returns.value()).map(Class::getSimpleName)
                                              .collect(Collectors.toList()))
                        .orElse(Collections.singletonList(method.getReturnType().getSimpleName()));
        grammar.setReturns(returnTypes);
        grammar.setFunction(function);
        grammar.setOwner(owner);
        return grammar;
    }

    private static boolean methodCheck(boolean mustStatic, Method method) {
        boolean isPublic = Modifier.isPublic(method.getModifiers());
        boolean b = Modifier.isStatic(method.getModifiers()) || !mustStatic;
        return isPublic && b;
    }
}
